#include "pch.h"
#include "CppUnitTest.h"
#include "Json.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

using namespace std;
using namespace SimpleJson;

namespace UnitTest
{

	TEST_CLASS(UnitTest)
	{
    private:
        const string jsonStr = "{ \
            \"id\":234, \
            \"weight\" : -63.25e+02, \
            \"name\" : \"\\u6211\\u662FSimpleJSON\", \
            \"num_array\" : [ \
                12.100000, \
                5.600000, \
                8.800000 \
            ] , \
            \"friend\" : { \
                \"id\":123, \
                \"weight\" : 63.250000, \
                \"name\" : \"SimpleNN\", \
                \"layers\" : [ \
                    \"convolution\", \
                    \"pooling\", \
                    \"affine\" \
                ] , \
                \"emmm\" : true \
            } \
        }";

	public:

		TEST_METHOD(TestLoad)
		{
            // load
            JsonParser parser(jsonStr);
            
            Json& root = parser.getRoot();
            Assert::IsTrue(root.getChildrenSize() > 0);
		}
       
        TEST_METHOD(TestSave)
        {
            // load
            JsonParser parser(jsonStr);

            // save
            string outJsonStr = "";
            parser.toString(outJsonStr, true);
            Assert::IsTrue(outJsonStr != "");
        }

        TEST_METHOD(TestGetRoot)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();
            Assert::AreEqual(5, root.getChildrenSize());
        }

        TEST_METHOD(TestSucceed)
        {
            // load
            JsonParser parser(jsonStr);
            Assert::IsTrue(parser.succeed());
        }

        TEST_METHOD(TestGetValueType)
        {
            JsonParser parser(jsonStr);

            Json& root = parser.getRoot();
            JsonValueType type = root["id"].getValueType();
            Assert::AreEqual((int)JSON_VALUE_TYPE_INT, (int)type);

            type = root["weight"].getValueType();
            Assert::AreEqual((int)JSON_VALUE_TYPE_DOUBLE, (int)type);

            type = root["name"].getValueType();
            Assert::AreEqual((int)JSON_VALUE_TYPE_STRING, (int)type);

            type = root["num_array"].getValueType();
            Assert::AreEqual((int)JSON_VALUE_TYPE_ARRAY, (int)type);

            type = root["friend"].getValueType();
            Assert::AreEqual((int)JSON_VALUE_TYPE_OBJECT, (int)type);

            type = root["friend"]["emmm"].getValueType();
            Assert::AreEqual((int)JSON_VALUE_TYPE_BOOL, (int)type);
        }

        TEST_METHOD(TestGetIntValue)
        {
            try
            {
                JsonParser parser(jsonStr);

                Json& root = parser.getRoot();
                int id = root["id"].getIntValue();
                Assert::AreEqual(234, id);
            }
            catch (const JsonTypeError& ex)
            {
                Logger::WriteMessage(ex.what());
            }
            catch (const JsonNullError& ex)
            {
                Logger::WriteMessage(ex.what());
            }
            catch (const exception& ex)
            {
                Logger::WriteMessage(ex.what());
            }
        }
        
        TEST_METHOD(TestGetDoubleValue)
        {
            JsonParser parser(jsonStr);

            Json& root = parser.getRoot();
            double weight = root["weight"].getDoubleValue();
            Assert::AreEqual(-63.25e+02, weight);
        }

        TEST_METHOD(TestGetBoolValue)
        {
            JsonParser parser(jsonStr);

            Json& root = parser.getRoot();
            bool weight = root["friend"]["emmm"].getBoolValue();
            Assert::AreEqual(true, weight);
        }

        TEST_METHOD(TestGetStringValue)
        {
            JsonParser parser(jsonStr);

            Json& root = parser.getRoot();
            string name = fromTString(root["friend"]["name"].getStringValue());
            Assert::AreEqual("SimpleNN", name.c_str());
        }
        
        TEST_METHOD(TestGetObjectValue)
        {
            JsonParser parser(jsonStr);

            Json& root = parser.getRoot();
            const Json::ObjValueType& obj = root["friend"].getObjectValue();
            Assert::AreEqual(5, (int)obj.size());
        }

        TEST_METHOD(TestGetArrayValue)
        {
            JsonParser parser(jsonStr);

            Json& root = parser.getRoot();
            const Json::ArrayValueType& arr = root["num_array"].getArrayValue();
            Assert::AreEqual(3, (int)arr.size());
        }

        TEST_METHOD(TestSetIntValue)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            root["id"].setValue(567);
            Assert::AreEqual(567, root["id"].getIntValue());
        }

        TEST_METHOD(TestSetDoubleValue)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            root["weight"].setValue(67.5);
            Assert::AreEqual(67.5, root["weight"].getDoubleValue());
        }

        TEST_METHOD(TestSetBoolValue)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            root["friend"]["emmm"].setValue(false);
            Assert::AreEqual(false, root["friend"]["emmm"].getBoolValue());
        }

        TEST_METHOD(TestSetStringValue)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            root["name"].setValue(toTString(string("jsonlib")));
            Assert::AreEqual("jsonlib", fromTString(root["name"].getStringValue()).c_str());
        }

        TEST_METHOD(TestSetObjectValue)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();
            
            Json::ObjValueType value;
            Json node(JSON_VALUE_TYPE_STRING);
            node.setValue("Bob");
            value["name"] = node;

            root["friend"].setValue(value);
            Assert::AreEqual(1, root["friend"].getChildrenSize());
        }

        TEST_METHOD(TestSetArrayValue)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            Json::ArrayValueType value;
            Json node(JSON_VALUE_TYPE_DOUBLE);
            node.setValue(99.9);
            value.push_back(node);
            root["num_array"].setValue(value);

            Assert::AreEqual(99.9, root["num_array"][0].getDoubleValue());
        }

        TEST_METHOD(TestGetChildrenSize)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            Assert::AreEqual(3, root["num_array"].getChildrenSize());
        }

        TEST_METHOD(TestPushBack)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            Json node(JSON_VALUE_TYPE_DOUBLE);
            node.setValue(99.9);

            root["num_array"].pushBack(node);
            Assert::AreEqual(99.9, root["num_array"][3].getDoubleValue());
        }

        TEST_METHOD(TestPushFront)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            Json node(JSON_VALUE_TYPE_DOUBLE);
            node.setValue(99.9);

            root["num_array"].pushFront(node);
            Assert::AreEqual(99.9, root["num_array"][0].getDoubleValue());
        }

        TEST_METHOD(TestClear)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            root["num_array"].clear();
            root["friend"].clear();
            Assert::AreEqual(0, root["num_array"].getChildrenSize());
            Assert::AreEqual(0, root["friend"].getChildrenSize());
        }

        TEST_METHOD(TestSetArray)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            root["optimizers"].setArray(3);
            Assert::AreEqual(3, root["optimizers"].getChildrenSize());
        }

        TEST_METHOD(TestArrayGet)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            double value = root["num_array"].arrayGet(0).getDoubleValue();
            Assert::AreEqual(12.1, value);
        }

        TEST_METHOD(TestArrayInsert)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();
            
            Json node(JSON_VALUE_TYPE_DOUBLE);
            node = 99.9;
            root["num_array"].arrayInsert(node, 2);
            Assert::AreEqual(99.9, root["num_array"].arrayGet(2).getDoubleValue());
        }

        TEST_METHOD(TestArrayErase)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            root["num_array"].arrayErase(0);
            Assert::AreEqual(2, root["num_array"].getChildrenSize());
        }

        TEST_METHOD(TestObjHasItem)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            bool isExists = root.objHasItem("id");
            Assert::AreEqual(true, isExists);

            isExists = root.objHasItem("lanxb");
            Assert::AreEqual(false, isExists);
        }

        TEST_METHOD(TestObjGetItem)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            int id = root.objGetItem("id").getIntValue();
            Assert::AreEqual(234, id);
        }

        TEST_METHOD(TestObjSetItem)
        {
            try
            {
                JsonParser parser(jsonStr);
                Json& root = parser.getRoot();

                Json value(JSON_VALUE_TYPE_INT);
                value.setValue(789);
                root.objSetItem("id", value);
                Assert::AreEqual(789, root["id"].getIntValue());
            }
            catch (const exception& ex)
            {
                Logger::WriteMessage(ex.what());
            }
        }

        TEST_METHOD(TestToJsonStr)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            string outStr = "";
            root["id"].toJsonStr(outStr);
            Assert::IsTrue(outStr != "");
        }

        TEST_METHOD(TestOperatorObjAdd)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            bool isExists = root.objHasItem("author");
            Assert::IsFalse(isExists);

            root["author"] = "lanxb";
            isExists = root.objHasItem("author");
            Assert::IsTrue(isExists);
        }

        TEST_METHOD(TestAsInt)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            int value = root["weight"].asInt();
            Assert::AreEqual(-6325, value);

            value = root["id"].asInt();
            Assert::AreEqual(234, value);

            value = root["friend"]["emmm"].asInt();
            Assert::AreEqual(1, value);
        }

        TEST_METHOD(TestAsDouble)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            double value = root["id"].asDouble();
            Assert::AreEqual(234.0, value);

            value = root["weight"].asDouble();
            Assert::AreEqual(-63.25e+02, value);

            value = root["friend"]["emmm"].asDouble();
            Assert::AreEqual(1.0, value);
        }

        TEST_METHOD(TestAsBool)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            bool value = root["id"].asBool();
            Assert::AreEqual(true, value);

            value = root["weight"].asDouble();
            Assert::AreEqual(true, value);

            value = root["friend"]["emmm"].asDouble();
            Assert::AreEqual(true, value);
        }

        TEST_METHOD(TestAsString)
        {
            JsonParser parser(jsonStr);
            Json& root = parser.getRoot();

            string value = root["id"].asString();
            Assert::AreEqual("234", value.c_str());

            value = root["weight"].asString();
            Assert::AreEqual("-6325.000000", value.c_str());

            value = root["friend"]["emmm"].asString();
            Assert::AreEqual("true", value.c_str());
        }

        TEST_METHOD(TestDirectConstructInt)
        {
            Json root = 1;
            Assert::AreEqual(1, root.getIntValue());
        }

        TEST_METHOD(TestDirectConstructDouble)
        {
            Json root = 1.5;
            Assert::AreEqual(1.5, root.getDoubleValue());
        }

        TEST_METHOD(TestDirectConstructBool)
        {
            Json root = false;
            Assert::AreEqual(false, root.getBoolValue());
        }

        TEST_METHOD(TestDirectConstructString)
        {
            Json root = "root";
            Assert::AreEqual("root", fromTString(root.getStringValue()).c_str());
        }

        TEST_METHOD(TestDirectConstructObj)
        {
            Json::ObjValueType obj;
            Json node = 100;
            obj["id"] = node;

            Json root = obj;
            Assert::AreEqual(1, root.getChildrenSize());

            Assert::AreEqual(100, root["id"].getIntValue());
        }

        TEST_METHOD(TestDirectConstructArray)
        {
            Json::ArrayValueType array;
            Json node = "lanxb";
            array.push_back(node);

            Json root = array;
            Assert::AreEqual(1, root.getChildrenSize());

            Assert::AreEqual("lanxb", fromTString(root[0].getStringValue()).c_str());
        }

	};
}
